package es.hekorusoft.udpcache.messages;

import java.io.ByteArrayOutputStream;

import net.sf.ehcache.Statistics;

/*
 This file is part of UDPCache.

 UDPCache is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 UDPCache is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with UDPCache.  If not, see <http://www.gnu.org/licenses/>.
 */
public final class ServerMessage {

	public enum OpCode {
		FOUND, NOT_FOUND, STATS;
	}

	private final Object obj;
	private final long seq;
	private final OpCode code;
	private final long expireTime;

	public ServerMessage(long seq, OpCode code, Object obj, long expireTime) {
		this.seq = seq;
		this.code = code;
		this.obj = obj;
		this.expireTime = expireTime;
	}

	public final Object getObj() {
		return obj;
	}

	public final long getSeq() {
		return seq;
	}

	public final OpCode getCode() {
		return code;
	}

	public final long getExpireTime() {
		return expireTime;
	}

	public final static ServerMessage foundMessage(long seq, byte[] array, long expireTime) {
		return new ServerMessage(seq, OpCode.FOUND, array, expireTime);
	}

	public final static ServerMessage cacheStatsMessage(long seq, Statistics stats) {
		return new ServerMessage(seq, OpCode.STATS, stats, 0);
	}

	public final static ServerMessage fromByte(byte[] data) {
		long seq = 0;
		OpCode code = null;
		long expireTime = 0;
		Object obj = null;

		StreamReader reader = new StreamReader(data);
		seq = reader.getLong();
		code = OpCode.values()[reader.getInt()];
		if (code != OpCode.NOT_FOUND) {
			expireTime = reader.getLong();
			obj = reader.getObject();
		}

		return new ServerMessage(seq, code, obj, expireTime);

	}

	public final byte[] toByteArray() {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		try {
			StreamWriter.addLong(seq, baos);
			StreamWriter.addInt(code.ordinal(), baos);
			if (obj != null) {
				StreamWriter.addLong(expireTime, baos);
				if (code != OpCode.STATS)
					StreamWriter.addByteArray((byte[]) obj, baos);
				else
					StreamWriter.addObject(obj, baos);
			}

			return baos.toByteArray();
		} catch (Exception ex) {
			ex.printStackTrace();
			return null;
		}
	}

	public final static ServerMessage notFoundMessage(long sequence) {
		return new ServerMessage(sequence, OpCode.NOT_FOUND, null, 0);
	}

	public final String toString() {
		return code + " - " + seq + " - " + expireTime + " - " + obj;
	}

}
